home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lfsrecov / lfsrecov.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-17  |  20.9 KB  |  689 lines

  1. /* 
  2.  * lfsrecov.c --
  3.  *
  4.  *    The lfsrecov program - Perform crash recovery on an LFS file system.
  5.  *    This program attempts to roll forward all changes made since the last
  6.  *    checkpoint. It also deals with deleted but still open files present at
  7.  *    shutdown or crash.
  8.  *
  9.  * Copyright 1989 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /user2/mendel/lfs/src/cmds/checkLfs/RCS/checkLfs.c,v 1.1 90/06/01 10:10:18 mendel Exp Locker: mendel $ SPRITE (Berkeley)";
  21. #endif /* not lint */
  22.  
  23. #include "lfslib.h"
  24. #include <stdio.h>
  25. #include <sys/types.h>
  26. #include <sys/file.h>
  27. #include <sys/param.h>
  28. #include <option.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <alloca.h>
  32. #include <bstring.h>
  33. #include <unistd.h>
  34. #include <bit.h>
  35. #include <time.h>
  36. #include <sys/time.h>
  37. #include <assert.h>
  38. #include <hash.h>
  39. #include <libc.h>
  40.  
  41. #include "lfsrecov.h"
  42. #include "desc.h"
  43. #include "dirlog.h"
  44. #include "fileop.h"
  45. #include "usage.h"
  46.  
  47. /*
  48.  * Start and end points of the tail of the recovery log.
  49.  */
  50. LogPoint    logStart;    /* Start of recovery log. */
  51. LogPoint    logEnd;        /* End of recovery log. */
  52.  
  53. Lfs    *lfsPtr;        /* File system being recovered. */
  54.  
  55. /*
  56.  * Arguments.
  57.  */
  58. int    blockSize = 512;    /* File system block size. */
  59. Boolean    verboseFlag = FALSE;    /* Trace progress of program. */
  60. Boolean    showLog = FALSE;    /* Show contents of log being processed. */
  61. char    *deviceName;        /* Device to use. */
  62. Boolean    writeFlag = FALSE;
  63. int    memAvail = 8*1024;    /* Amount of data to cache size in kilobytes. */
  64. Boolean    statsFlag = FALSE;
  65. char    *statDir = "/sprite/lfsstats"; 
  66. /*
  67.  * Testing options.
  68.  */
  69.  
  70. Boolean recreateDirEntries = FALSE; /* Recreate any directory entries. */
  71. int    testWait = 0;            /* Time to wait after reading checkpoint
  72.                      * and before recovery. */
  73. Boolean    testCheck = FALSE;       /* Test recovery by checkpoint against
  74.                     * checkpoint. */
  75.  
  76. Option optionArray[] = {
  77.     {OPT_DOC, (char *) NULL,  (char *) NULL,
  78.     "Recovery a LFS file system.\n Synopsis: \"lfsrecov [switches] deviceName\"\n Command-line switches are:"},
  79.     {OPT_TRUE, "write", (Address) &writeFlag, 
  80.     "Write changes to disk."},
  81.     {OPT_INT, "memAvail", (Address) &memAvail, 
  82.     "Kilobytes of memory available to the recovery program."},
  83.     {OPT_TRUE, "stats", (Address) &statsFlag, 
  84.     "Write stats to disk."},
  85.     {OPT_STRING, "statDir", (Address) &statDir, 
  86.     "Directory to put stats from recovery."},
  87.     {OPT_DOC, (char *) NULL,  (char *) NULL,
  88.     "The following options are for debugging and testing:"},
  89.     {OPT_TRUE, "showLog", (Address) &showLog, 
  90.     "Show contents of log being processed."},
  91.     {OPT_TRUE, "verbose", (Address) &verboseFlag, 
  92.     "Output progress messages during execution."},
  93.     {OPT_TRUE, "recreateDirEntries", (Address) &recreateDirEntries, 
  94.     "For testing, recreate any directory from checkpoint."},
  95.     {OPT_INT, "testWait", (Address) &testWait, 
  96.     "For testing, wait after reading checkpoint."},
  97.     {OPT_TRUE, "testCheck", (Address) &testCheck, 
  98.     "For testing, check against checkpoint."},
  99. };
  100.  
  101.  
  102. LogPoint testLogEnd;    /* Log end for testing purposes. */
  103. caddr_t  startSbrk;    /* Starting sbrk() value for program. Used to 
  104.                track program size. */
  105. Stats    stats;
  106.  
  107. /*
  108.  * Forward routine declartions.
  109.  */
  110.  
  111. static Boolean WriteOutStats _ARGS_((FILE *fd, Boolean noWork));
  112.  
  113. static double timediff _ARGS_((struct timeval *ep, struct timeval *sp));
  114.  
  115. static Boolean ScanRecoveryLog _ARGS_((Lfs *lfsPtr, enum Pass pass));
  116.  
  117. extern void RollMetaDataForward _ARGS_((Lfs *lfsPtr));
  118.  
  119.  
  120. void CompareCheckpoints _ARGS_((Lfs *lfsPtr, Lfs *newLfsPtr));
  121.  
  122. /*
  123.  * System routines not defined in header files. 
  124.  */
  125.  
  126. extern caddr_t sbrk _ARGS_((int numBytes));
  127. extern int  fsync _ARGS_((int fd));
  128.  
  129.  
  130. /*
  131.  *----------------------------------------------------------------------
  132.  *
  133.  * main --
  134.  *
  135.  *    Main routine of lfsrecov - parse arguments and do the work.
  136.  *
  137.  * Results:
  138.  *    0 if file system was successfully recovered.
  139.  *    1 if problem found.
  140.  *
  141.  * Side effects:
  142.  *    None.
  143.  *
  144.  *----------------------------------------------------------------------
  145.  */
  146.  
  147. int
  148. main(argc,argv)
  149.     int    argc;
  150.     char *argv[];
  151. {
  152.     ReturnStatus    status;
  153.     Boolean         needRecovery;
  154.     Lfs        *newLfsPtr;
  155.  
  156.     /*
  157.      * Parse the arguments and open the device containing the file system.
  158.      */
  159.  
  160.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray), 0);
  161.     if (argc != 2) { 
  162.          Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
  163.      exit(1);
  164.     } else {
  165.     deviceName = argv[1];
  166.     }
  167.     if (testCheck) {
  168.     startSbrk = sbrk(0);
  169.     }
  170.     gettimeofday(&stats.startTimeOfDay, (struct timezone *) NULL);
  171.  
  172.     lfsPtr = LfsLoadFileSystem(argv[0], deviceName, blockSize, 
  173.             LFS_SUPER_BLOCK_OFFSET, writeFlag ? O_RDWR : O_RDONLY);
  174.     if (lfsPtr == (Lfs *) NULL) {
  175.     exit(1);
  176.     }
  177.     if (testWait > 0) {
  178.     sleep(testWait);
  179.     }
  180.     if (testCheck) {
  181.     newLfsPtr = LfsLoadFileSystem(argv[0], deviceName, blockSize,
  182.                 LFS_SUPER_BLOCK_OFFSET, O_RDONLY);
  183.     if (newLfsPtr  == (Lfs *) NULL) {
  184.         fprintf(stderr, "Can't load file system to check.\n");
  185.         testCheck = FALSE;
  186.     } else { 
  187.         testLogEnd = newLfsPtr->logEnd;
  188.     }
  189.     } else {
  190.     newLfsPtr  = (Lfs *) NULL;
  191.     }
  192.     stats.crashTime = lfsPtr->checkPointHdrPtr->detachSeconds;
  193.     stats.timestamp = lfsPtr->checkPointHdrPtr->timestamp;
  194.     stats.loadBlockReads = lfsPtr->pstats.blocksReadDisk;
  195.  
  196.     LfsDiskCache(lfsPtr, memAvail*1024);
  197.     if (verboseFlag) {
  198.     printf("Starting Pass 1 on %s\n", lfsPtr->name);
  199.     }
  200.     gettimeofday(&stats.startPass1TimeOfDay, (struct timezone *) NULL);
  201.     needRecovery = ScanRecoveryLog(lfsPtr, PASS1);
  202.  
  203.     stats.pass1BlockReads = lfsPtr->pstats.blocksReadDisk - 
  204.                 stats.loadBlockReads;
  205.     if (!needRecovery) {
  206.     if (verboseFlag) {
  207.         printf("No recovery needed for %s\n", lfsPtr->name);
  208.     }
  209.     goto dumpStats;
  210.     }
  211.  
  212.     RollMetaDataForward(lfsPtr);
  213.  
  214.     if (verboseFlag) {
  215.     printf("Starting Pass 2 on %s\n", lfsPtr->name);
  216.     }
  217.     gettimeofday(&stats.startPass2TimeOfDay, (struct timezone *) NULL);
  218.     ScanRecoveryLog(lfsPtr, PASS2);
  219.  
  220.     stats.pass2BlockReads = lfsPtr->pstats.blocksReadDisk - 
  221.                 stats.loadBlockReads - stats.pass1BlockReads;
  222.     UpdateLost_Found(lfsPtr);
  223.  
  224.     if (testCheck) {
  225.     CompareCheckpoints(lfsPtr, newLfsPtr);
  226.     }
  227.     gettimeofday(&stats.startWriteTimeOfDay, (struct timezone *) NULL);
  228.     if (writeFlag) {
  229.     if (verboseFlag) {
  230.         printf("Checkpointing changes to %s\n", lfsPtr->name);
  231.     }
  232.     status = LfsCheckPointFileSystem(lfsPtr, 0);
  233.     if (status != SUCCESS) {
  234.         exit(1);
  235.     }
  236.     }
  237.  dumpStats:
  238.     gettimeofday(&stats.endTimeOfDay, (struct timezone *) NULL);
  239.     if (statsFlag) {
  240.     char statsFileName[MAXPATHLEN];
  241.     FILE    *fd;
  242.     (void) sprintf(statsFileName, "%d/%s", statDir, lfsPtr->name);
  243.     fd = fopen(statsFileName, "a");
  244.     if (fd == (FILE *) NULL) {
  245.         perror(statsFileName);
  246.         fprintf(stderr,"Can't open stats file\n");
  247.     } else {
  248.         if (!WriteOutStats(fd, needRecovery)) {
  249.         fprintf(stderr,"Can't write stats file\n");
  250.         }
  251.         if (fsync(fileno(fd)) != 0) {
  252.         perror("fsync");
  253.         fprintf(stderr,"Can't fsync stats file\n");
  254.         }
  255.         fclose(fd);
  256.     }
  257.     }
  258.     exit(0);
  259.     return 0;
  260. }
  261.  
  262. /*
  263.  *----------------------------------------------------------------------
  264.  *
  265.  * ScanRecoveryLog --
  266.  *
  267.  *    Perform recovery by scanning thru the tail of the log.
  268.  *    During PASS1 The segments and inodes written since the last 
  269.  *      checkpoint checkpoint are recovered.
  270.  *
  271.  * Results:
  272.  *    TRUE if recovery is need. FALSE if checkpoint is up to date.
  273.  *
  274.  * Side effects:
  275.  *    None.
  276.  *
  277.  *----------------------------------------------------------------------
  278.  */
  279. static Boolean
  280. ScanRecoveryLog(lfsPtr, pass)
  281.     Lfs    *lfsPtr;    /*  The file system. */
  282.     enum Pass pass;    /* The pass number. */
  283. {
  284.     int startAddr, nextSeg = -1;
  285.     int    startingTimeStamp; /* Starting timestamp of checkpoint. */
  286.     int    endingTimeStamp;   /* Maximum ending time. */
  287.     char *summaryLimitPtr, *summaryPtr;
  288.     LfsSegSummary *segSummaryPtr;
  289.     LfsSegSummaryHdr *segSummaryHdrPtr;
  290.     LogPoint    curLoc;
  291.     LfsSeg    *segPtr;
  292.     Boolean done;
  293.     int         addr;
  294.  
  295.  
  296.     endingTimeStamp = startingTimeStamp = lfsPtr->checkPointHdrPtr->timestamp;
  297.  
  298.     /*
  299.      * Move forward thru the recovery log. 
  300.      */
  301.     logStart = lfsPtr->logEnd;
  302.     if (verboseFlag && (pass == PASS1)) {
  303.     printf("Recovery log starts at <%d,%d> at %d\n", 
  304.             logStart.segNo, logStart.blockOffset,
  305.             startingTimeStamp);
  306.     }
  307.     for(curLoc = logStart, done = FALSE; !done; ) { 
  308.         segPtr = LfsSegInit(lfsPtr, curLoc.segNo);
  309.         startAddr = LfsSegStartAddr(segPtr) + LfsSegSizeInBlocks(lfsPtr);
  310.     do { 
  311.         /*
  312.          * During testing, check to see if we hit the end checkpoint.
  313.          */
  314.         if (testCheck && 
  315.         (testLogEnd.blockOffset == curLoc.blockOffset) &&
  316.         (testLogEnd.segNo == curLoc.segNo)) {
  317.         done = TRUE;
  318.         break;
  319.         }
  320.         if (pass == PASS1) { 
  321.         stats.segSummaryFetch++;
  322.         }
  323.         /*
  324.          * Spin thru the summary blocks of this segment. We know we
  325.          * have reached end of log if:
  326.          * 1) The summary region is zero (ie size of zero). 
  327.          * 2) The summary region is not valid. 
  328.          * 3) The timestamp went backward.
  329.          * All this means that the write that was to generated the
  330.          * data didn't complete.
  331.          */
  332.         segSummaryPtr = (LfsSegSummary *) 
  333.             LfsSegFetchBlock(segPtr, curLoc.blockOffset, blockSize);
  334.         if (segSummaryPtr->size == 0) {
  335.         LfsSegReleaseBlock(segPtr, (char *) segSummaryPtr);
  336.         done = TRUE;
  337.         break;
  338.         }
  339.         if (segSummaryPtr->magic != LFS_SEG_SUMMARY_MAGIC) {
  340.         fprintf(stderr,"%s: Bad magic number 0x%x for summary region of segment %d\n", deviceName, segSummaryPtr->magic, curLoc.segNo);
  341.         done = TRUE;
  342.         break;
  343.         }
  344.         if (segSummaryPtr->timestamp < startingTimeStamp) {
  345.         done = TRUE;
  346.         break;
  347.         }
  348.         if (verboseFlag) {
  349.         printf("Scaning summary @ <%d,%d> time %d\n", curLoc.segNo, 
  350.                  curLoc.blockOffset, segSummaryPtr->timestamp);
  351.         }
  352.         endingTimeStamp = segSummaryPtr->timestamp;
  353.         if (pass == PASS1) { 
  354.         /*
  355.          * Record the segment as part of the recovery log if we haven't
  356.          * already.
  357.          */
  358.         RecordSegInLog(curLoc.segNo, curLoc.blockOffset);
  359.         addr = startAddr-curLoc.blockOffset;
  360.         if (showLog) { 
  361.             printf("Addr %d Summary Time %d PrevSeg %d NextSeg %d bytes %d NextSum %d\n",
  362.             addr,
  363.             segSummaryPtr->timestamp, segSummaryPtr->prevSeg, 
  364.             segSummaryPtr->nextSeg,
  365.             segSummaryPtr->size, segSummaryPtr->nextSummaryBlock);
  366.         }
  367.         }
  368.         curLoc.blockOffset++;
  369.         /*
  370.          * Scan thru this summary region.
  371.          */
  372.         summaryLimitPtr = (char *) segSummaryPtr + segSummaryPtr->size;
  373.         summaryPtr = (char *) (segSummaryPtr + 1);
  374.         while (summaryPtr < summaryLimitPtr) {
  375.            addr = startAddr-curLoc.blockOffset;
  376.            segSummaryHdrPtr = (LfsSegSummaryHdr *) summaryPtr;
  377.            if (segSummaryHdrPtr->lengthInBytes == 0) {
  378.             break;
  379.            }
  380.            switch (segSummaryHdrPtr->moduleType) { 
  381.            case LFS_SEG_USAGE_MOD:
  382.               RecovSegUsageSummary(lfsPtr, pass, segPtr, addr,
  383.                    curLoc.blockOffset,  segSummaryHdrPtr);
  384.                break;
  385.            case LFS_DESC_MAP_MOD:
  386.               RecovDescMapSummary(lfsPtr, pass, segPtr, addr,
  387.                    curLoc.blockOffset,  segSummaryHdrPtr);
  388.               break;
  389.            case LFS_FILE_LAYOUT_MOD:
  390.               RecovFileLayoutSummary(lfsPtr, pass, segPtr, addr,
  391.                    curLoc.blockOffset,  segSummaryHdrPtr);
  392.               break;
  393.            default: 
  394.             fprintf(stderr,"%s:CheckSummary: Unknown module type %d at %d, Size %d Blocks %d\n",
  395.                 deviceName, segSummaryHdrPtr->moduleType, addr,
  396.                 segSummaryHdrPtr->lengthInBytes, 
  397.                 segSummaryHdrPtr->numDataBlocks);
  398.             break;
  399.            }
  400.            summaryPtr += segSummaryHdrPtr->lengthInBytes;
  401.            curLoc.blockOffset += (segSummaryHdrPtr->numDataBlocks-1);
  402.        }
  403.        /*
  404.         * On to the next summary block.  
  405.         */
  406.        if (segSummaryPtr->nextSummaryBlock == -1) { 
  407.            curLoc.blockOffset = 0;
  408.        } else {
  409.            curLoc.blockOffset = segSummaryPtr->nextSummaryBlock-1;
  410.        }
  411.        nextSeg = segSummaryPtr->nextSeg;
  412.         LfsSegReleaseBlock(segPtr, (char *) segSummaryPtr);
  413.     } while( curLoc.blockOffset != 0);
  414.     /*
  415.      * On to the next segment.
  416.      */
  417.     LfsSegRelease(segPtr);
  418.     if (!done) { 
  419.         curLoc.segNo = nextSeg;
  420.         curLoc.blockOffset = 0;
  421.     }
  422.     }
  423.     logEnd = curLoc;
  424.     if (verboseFlag && (pass == PASS1)) {
  425.     printf("Recovery log end at <%d,%d> at %d\n", 
  426.             logEnd.segNo, logEnd.blockOffset,
  427.             endingTimeStamp);
  428.     }
  429.     return ((logEnd.segNo != logStart.segNo) || 
  430.         (logEnd.blockOffset != logStart.blockOffset));
  431. }
  432.  
  433.  
  434. /*
  435.  *----------------------------------------------------------------------
  436.  *
  437.  * RollMetaDataForward --
  438.  *
  439.  *    Roll forward the changes to the metadata structure caused
  440.  *    by the descriptors going out to the recovery log.
  441.  *
  442.  * Results:
  443.  *    None.
  444.  *
  445.  * Side effects:
  446.  *    None.
  447.  *
  448.  *----------------------------------------------------------------------
  449.  */
  450.  
  451. void
  452. RollMetaDataForward(lfsPtr)
  453.     Lfs    *lfsPtr;
  454. {
  455.     ClientData clientData;
  456.     int        fileNumber;
  457.     int        address;
  458.     LfsFileDescriptor    *descPtr;
  459.  
  460.     RollSegUsageForward(lfsPtr);
  461.  
  462.     /*
  463.      * Next, scan thru all the descriptors in the recovery log. Update
  464.      * the descriptor map and segment usage table.
  465.      */
  466.      clientData = (ClientData) NIL;
  467.      while (ScanNewDesc(&clientData, &fileNumber, &address, &descPtr)) {
  468.      if (descPtr == (LfsFileDescriptor *) NIL) {
  469.          address = FSDM_NIL_INDEX;
  470.          stats.descDelete++;
  471.      } else {
  472.          stats.descMove++;
  473.      }
  474.      RecoveryFile(fileNumber, address, descPtr);
  475.      }
  476.      ScanNewDescEnd(&clientData);
  477.  
  478. }
  479.  
  480.  
  481. /*
  482.  *----------------------------------------------------------------------
  483.  *
  484.  * WriteOutStats --
  485.  *
  486.  *    Write out program stats.
  487.  *
  488.  * Results:
  489.  *    TRUE if write worked, FALSE if an error occurred.
  490.  *
  491.  * Side effects:
  492.  *    None.
  493.  *
  494.  *----------------------------------------------------------------------
  495.  */
  496. static Boolean
  497. WriteOutStats(fd, noWork)
  498.     FILE *fd;    /* File to write stats to. */
  499.     Boolean noWork;
  500. {
  501.     time_t t = time((time_t *)NULL);
  502.  
  503.     fprintf(fd, "date: %s\n", ctime(&t));
  504.     fprintf(fd, "name: %s\n", lfsPtr->name);
  505.     fprintf(fd, "checkpointInterval: %d\n", 
  506.             lfsPtr->superBlock.hdr.checkpointInterval);
  507.     fprintf(fd, "crashTime: %d\n", stats.crashTime);
  508.     fprintf(fd, "timestamp: %d\n", stats.timestamp);
  509.     fprintf(fd, "noWork: %d\n", noWork);
  510.     fprintf(fd, "totalTime: %f\n", 
  511.         timediff(&stats.endTimeOfDay, &stats.startTimeOfDay)); 
  512.     fprintf(fd, "loadTime: %f\n", 
  513.         timediff(&stats.startPass1TimeOfDay, &stats.startTimeOfDay)); 
  514.     fprintf(fd, "pass1Time: %f\n", 
  515.     timediff(&stats.startPass2TimeOfDay, &stats.startPass1TimeOfDay)); 
  516.     if (!noWork) {
  517.     fprintf(fd, "pass2Time: %f\n", 
  518.         timediff(&stats.startWriteTimeOfDay, &stats.startPass2TimeOfDay)); 
  519.     fprintf(fd, "writeTime: %f\n", 
  520.         timediff(&stats.endTimeOfDay, &stats.startWriteTimeOfDay)); 
  521.     }
  522. #define    PSF(FIELD, NAME)  fprintf(fd, "%s: %d\n", NAME, stats.FIELD);
  523.     PSF(numLogSegments, "numLogSegments");
  524.     PSF(segSummaryFetch, "segSummaryFetch");
  525.     PSF(descMapBlocks, "descMapBlocks");
  526.     PSF(descBlocks, "descBlocks");
  527.     PSF(numDesc, "numDesc");
  528.     PSF(numFileBlocks, "numFileBlocks");
  529.     PSF(numDirLogBlocks, "numDirLogBlocks");
  530.     PSF(numDirLogEntries, "numDirLogEntries");
  531.     PSF(numDirLogDelete, "numDirLogDelete");
  532.     PSF(numDirLogDeleteOpen, "numDirLogDeleteOpen");
  533.     PSF(numDirLogUnlink, "numDirLogUnlink");
  534.     PSF(numDirLogCreate, "numDirLogCreate");
  535.     PSF(numDirLogWithoutEnd, "numDirLogWithoutEnd");
  536.     PSF(dirLogBothForward, "dirLogBothForward");
  537.     PSF(dirLogDirBlockBackward, "dirLogDirBlockBackward");
  538.     PSF(dirLogBothBackwardCreate, "dirLogBothBackwardCreate");
  539.     PSF(dirLogBothBackward, "dirLogBothBackward");
  540.     PSF(descDelete, "descDelete");
  541.     PSF(descMove, "descMove");
  542.     PSF(filesToLostFound, "filesToLostFound");
  543.     PSF(dirEntryAdded, "dirEntryAddeds");
  544.     PSF(dirEntryRemoved, "dirEntryRemoved");
  545.     PSF(loadBlockReads, "loadBlockReads");
  546.     PSF(pass1BlockReads, "pass1BlockReads");
  547.     PSF(pass2BlockReads, "pass2BlockReads");
  548. #undef PSF
  549.     fprintf(fd, "LfsblocksReadDisk: %d\n", lfsPtr->pstats.blocksReadDisk);
  550.     fprintf(fd, "LfsblocksWrittenDisk: %d\n", lfsPtr->pstats.blocksWrittenDisk);
  551.     fprintf(fd, "LfswriteSummaryBlock: %d\n", lfsPtr->pstats.writeSummaryBlock);
  552.     fprintf(fd, "LfssegUsageBlockWrite: %d\n", lfsPtr->pstats.segUsageBlockWrite);
  553.     fprintf(fd, "LfsdescMapBlockWrite: %d\n", lfsPtr->pstats.descMapBlockWrite);
  554.     fprintf(fd, "LfsfileWritten: %d\n", lfsPtr->pstats.fileWritten);
  555.     fprintf(fd, "LfsfileBlockWritten: %d\n", 
  556.         lfsPtr->pstats.fileBlockWritten);
  557.     fprintf(fd, "LfsdescWritten: %d\n", 
  558.         lfsPtr->pstats.descWritten);
  559.     return !ferror(fd);
  560. }
  561.  
  562. /*
  563.  *----------------------------------------------------------------------
  564.  *
  565.  * timediff --
  566.  *
  567.  *    Compute the difference in seconds between two timevals. 
  568.  *
  569.  * Results:
  570.  *    Difference in seconds
  571.  *
  572.  * Side effects:
  573.  *    None.
  574.  *
  575.  *----------------------------------------------------------------------
  576.  */
  577.  
  578.  
  579. static double
  580. timediff (ep,sp)
  581.     struct timeval *ep;        /* End value. */
  582.     struct timeval *sp;        /* Start value. */
  583. {
  584.     double seconds;
  585.  
  586.     seconds = (ep->tv_sec - sp->tv_sec)
  587.                + (ep->tv_usec - sp->tv_usec)/1000000.0;
  588.  
  589.     return seconds;
  590. }
  591.  
  592. /*
  593.  *----------------------------------------------------------------------
  594.  *
  595.  * CompareCheckpoints --
  596.  *
  597.  *    Compare the recovery generated checkpoint against the system
  598.  *     generated one during testing
  599.  *
  600.  * Results:
  601.  *    None.
  602.  *
  603.  * Side effects:
  604.  *    None.
  605.  *
  606.  *----------------------------------------------------------------------
  607.  */
  608.  
  609. void
  610. CompareCheckpoints(lfsPtr, newLfsPtr)
  611.     Lfs    *lfsPtr;    /* Recovery generated one. */
  612.     Lfs *newLfsPtr;    /* System generated one. */
  613. {
  614.     LfsDescMapCheckPoint *dCpPtr, *dNewCpPtr;
  615.     LfsSegUsageCheckPoint *sCpPtr, *sNewCpPtr;
  616.     int    segNum, fileNumber, numSegs, blockNum;
  617.     int *adjustmentArray;
  618.     /* 
  619.      * Compare descriptor map data structure. 
  620.      */
  621.     dCpPtr = &lfsPtr->descMap.checkPoint;
  622.     dNewCpPtr = &newLfsPtr->descMap.checkPoint;
  623.  
  624.     if (dCpPtr->numAllocDesc != dNewCpPtr->numAllocDesc) {
  625.     fprintf(stderr,"CompareCheckpoints: descMap numAllocDesc my %d ckp %d\n",
  626.         dCpPtr->numAllocDesc, dNewCpPtr->numAllocDesc);
  627.     }
  628.     for (fileNumber = 0; fileNumber < lfsPtr->superBlock.descMap.maxDesc; 
  629.      fileNumber++) {
  630.     LfsDescMapEntry    *entryPtr, *newEntryPtr;
  631.     entryPtr = LfsGetDescMapEntry(lfsPtr, fileNumber);
  632.     newEntryPtr = LfsGetDescMapEntry(newLfsPtr, fileNumber);
  633.     if ((entryPtr->flags == newEntryPtr->flags) &&
  634.         !(entryPtr->flags & LFS_DESC_MAP_ALLOCED)) {
  635.        continue;
  636.     }
  637. #define    C(FIELD, NAME) if(entryPtr->FIELD != newEntryPtr->FIELD) { fprintf(stderr, "CompareCheckpoints: File %d descMap %s my %d ckp %d\n", fileNumber, NAME, entryPtr->FIELD, newEntryPtr->FIELD); }
  638.     C(blockAddress, "blockAddress");
  639.     C(flags, "flags"); C(truncVersion, "truncVersion");
  640.     C(accessTime, "accessTime");
  641. #undef C
  642.     }
  643.  
  644.     /*
  645.      * Compare seg usage map.
  646.      */
  647.     sCpPtr = &lfsPtr->usageArray.checkPoint;
  648.     sNewCpPtr = &newLfsPtr->usageArray.checkPoint;
  649.  
  650. #define    C(FIELD, NAME) if(sCpPtr->FIELD != sNewCpPtr->FIELD) { fprintf(stderr, "CompareCheckpoints: segUsage %s my %d ckp %d\n", NAME, sCpPtr->FIELD, sNewCpPtr->FIELD); }
  651.     C(freeBlocks, "freeBlocks"); C(numClean, "numClean");
  652.     C(numDirty, "numDirty"); C(dirtyActiveBytes, "dirtyActiveBytes");
  653.     C(currentSegment, "currentSegment"); 
  654.     C(currentBlockOffset, "currentBlockOffset");
  655.     C(curSegActiveBytes, "curSegActiveBytes"); 
  656.     C(previousSegment, "previousSegment");
  657.     C(cleanSegList, "cleanSegList"); 
  658. #undef C
  659.  
  660.     numSegs = lfsPtr->superBlock.usageArray.numberSegments;
  661.     adjustmentArray = (int *) alloca(numSegs * sizeof(adjustmentArray[0]));
  662.     bzero((char *)adjustmentArray, numSegs * sizeof(adjustmentArray[0]));
  663.     for (blockNum = 0; blockNum < lfsPtr->superBlock.usageArray.stableMem.maxNumBlocks; blockNum++) {
  664.     int    oldBlock, newBlock;
  665.     oldBlock = LfsGetUsageArrayBlockIndex(lfsPtr, blockNum);
  666.     newBlock = LfsGetUsageArrayBlockIndex(newLfsPtr, blockNum);
  667.     adjustmentArray[LfsDiskAddrToSegmentNum(lfsPtr, oldBlock)] -= 
  668.             lfsPtr->superBlock.usageArray.stableMem.blockSize;
  669.     adjustmentArray[LfsDiskAddrToSegmentNum(lfsPtr, newBlock)] += 
  670.             lfsPtr->superBlock.usageArray.stableMem.blockSize;
  671.  
  672.     }
  673.     for (segNum = 0; segNum < numSegs; segNum++) {
  674.     LfsSegUsageEntry    *entryPtr, *newEntryPtr;
  675.     entryPtr = LfsGetUsageArrayEntry(lfsPtr, segNum);
  676.     newEntryPtr = LfsGetUsageArrayEntry(newLfsPtr, segNum);
  677.     if ((entryPtr->flags == newEntryPtr->flags) &&
  678.         (entryPtr->flags & LFS_SEG_USAGE_CLEAN)) {
  679.        continue;
  680.     }
  681. #define    C(ADJ, FIELD, NAME) if(ADJ + entryPtr->FIELD != newEntryPtr->FIELD) { fprintf(stderr, "CompareCheckpoints: Seg %d entry %s my %d ckp %d\n", segNum, NAME, ADJ + entryPtr->FIELD, newEntryPtr->FIELD); }
  682.     C(adjustmentArray[segNum], activeBytes, "activeBytes");
  683.     C(0, timeOfLastWrite, "timeOfLastWrite"); C(0, flags, "flags");
  684. #undef C
  685.     }
  686.     printf("Memend = %d (growth = %d)\n", (int)sbrk(0), sbrk(0) - startSbrk);
  687.  
  688. }
  689.